using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using PloobsEngine.Utils;

namespace PloobsEngine.Modelo
{
    /// <summary>
    /// Modelo simples, igual ao do Xna Model
    /// </summary>
    public class SimpleModel : IModelo
    {
        public void Serialize(System.Xml.XmlTextWriter textWriter)
        {
            SerializerHelper.SerializeBaseType<string>(Name, "Name", textWriter);
            SerializerHelper.SerializeBaseType<string>(textureName, "TextureName", textWriter);
            SerializerHelper.SerializeBaseType<string>(_bumpName, "BumpName", textWriter);
            SerializerHelper.SerializeBaseType<string>(_specularName, "SpecularName", textWriter);
            SerializerHelper.SerializeBaseType<string>(_glowName, "glowName", textWriter);
            SerializerHelper.SerializeBaseType<string>(_paralaxName, "paralaxName", textWriter);
        }
        public void DeSerialize(System.Xml.XmlNode node,EngineStuff engine)
        {
            this.Name =  SerializerHelper.DeserializeBaseType<string>("Name", node);
            this.textureName = SerializerHelper.DeserializeBaseType<string>("TextureName", node);
            this._bumpName = SerializerHelper.DeserializeBaseType<string>("BumpName", node);
            this._specularName = SerializerHelper.DeserializeBaseType<string>("SpecularName", node);
            this._glowName = SerializerHelper.DeserializeBaseType<string>("glowName", node);
            this._paralaxName = SerializerHelper.DeserializeBaseType<string>("paralaxName", node);
            this.LoadModelo();

        }

        private const string CUSTOM = "CUSTOM";

        private string _paralaxName = null;

        public string ParalaxName
        {
            get { return _paralaxName; }
            set { _paralaxName = value; }
        }

        private string _glowName = null;

        public string GlowName
        {
            get { return _glowName; }
            set { _glowName = value; }
        }

        private string _bumpName = null;

        public string BumpMapName
        {
            get { return _bumpName; }
            set { _bumpName = value; }
        }
        private string _specularName = null;

        public string SpecularMapName
        {
            get { return _specularName; }
            set { _specularName = value; }
        }

        public String DiffuseMapName
        {
            get { return textureName; }
            set { textureName = value; }
        }

        private String _name;              
        /// <summary>
        /// Xna Model
        /// </summary>
        private Model _model;

        public Model Model
        {
            get { return _model; }
            set { _model = value; }
        }

        /// <summary>
        /// Serialization 
        /// </summary>
        public SimpleModel()
        {
        }

         public SimpleModel(String name)
        {
            this._name = name;
        }

         public SimpleModel(String name, String diffuseName)
         {
             this._name = name;
             this.textureName = diffuseName;
         }

         public SimpleModel(String name, String diffuseName,String bumpName)
         {
             this._name = name;
             this.textureName = diffuseName;
             this._bumpName = bumpName;
         }
         
         public SimpleModel(String name, String diffuseName,String bumpName,String specularName)
         {
             this._name = name;
             this.textureName = diffuseName;
             this._bumpName = bumpName;
             this._specularName = specularName;
         }


         public SimpleModel(String name, String diffuseName, String bumpName, String specularName,String glowName)
         {
             this._name = name;
             this.textureName = diffuseName;
             this._bumpName = bumpName;
             this._specularName = specularName;
             this._glowName = glowName;
         }

         public SimpleModel(String name, String diffuseName, String bumpName, String specularName, String glowName, String paralaxName)
         {
             this._name = name;
             this.textureName = diffuseName;
             this._bumpName = bumpName;
             this._specularName = specularName;
             this._glowName = glowName;
             this._paralaxName = paralaxName;
         }  
        
        /// <summary>
        /// Carrega o modelo e o shadder
        /// </summary>
        /// <param name="gd"></param>
        public void LoadModelo()
        {
            this._model = EngineStuff.CustomContentManager.GetAsset<Model>(this._name);
            if (!String.IsNullOrEmpty(textureName) && textureName != CUSTOM) 
            {
                this.texture = EngineStuff.CustomContentManager.GetAsset<Texture2D>(textureName);
            }
            if (!String.IsNullOrEmpty(_bumpName) && _bumpName != CUSTOM)
            {
                this.bump = EngineStuff.CustomContentManager .GetAsset<Texture2D>(_bumpName);
            }
            if (!String.IsNullOrEmpty(_specularName) && _specularName != CUSTOM)
            {
                this.specular = EngineStuff.CustomContentManager.GetAsset<Texture2D>(_specularName);
            }
            if (!String.IsNullOrEmpty(_glowName) && _glowName != CUSTOM)
            {
                this.glow = EngineStuff.CustomContentManager.GetAsset<Texture2D>(_glowName);
            }
            if (!String.IsNullOrEmpty(_paralaxName) && _paralaxName != CUSTOM)
            {
                this.paralax= EngineStuff.CustomContentManager.GetAsset<Texture2D>(_paralaxName);
            }

            if (vertexBufferS != null || indexBufferS == null || batchInformationS == null)
            {
                ModelBuilderHelper.Extract(_model, out batchInformationS, out vertexBufferS, out indexBufferS);
            }
        }

        #region IModelo Members

        public string Name
        {
            get { return this._name; }
            set { this._name = value; }
        }

        #endregion

        #region IModelo Members

        String textureName = null;
        Texture2D texture = null;
        Texture2D bump = null;
        Texture2D specular = null;
        Texture2D glow = null;
        Texture2D paralax = null;
        ModelMesh[]  mesh= null;

        public ModelMesh[] getModelMeshes()
        {
            if(mesh == null)
            {
                mesh = new ModelMesh[_model.Meshes.Count];
                _model.Meshes.CopyTo(mesh, 0);
            }
                return mesh;
        }


        public void SetTexture(String textureName ,TextureType type)
        {
            switch (type)
	        {
		        case TextureType.DIFFUSE:
                  this.textureName = textureName;
                 break;
                case TextureType.SPECULAR:
                 this._specularName = textureName;
                 break;
                case TextureType.BUMP:
                 this._bumpName = textureName;
                 break;
                case TextureType.GLOW:
                 this._specularName = textureName;
                 break;
                case TextureType.PARALAX:
                 this._paralaxName = textureName;
                 break;
                default:
                 throw new Exception("Invalid Buffer");                 
	        }

            LoadModelo();
        }

        public void SetTexture(Texture2D tex, TextureType type)
        {
            switch (type)
            {
                case TextureType.DIFFUSE:
                    this.textureName = "CUSTOM";
                    this.texture = tex;
                    break;
                case TextureType.SPECULAR:
                    this.textureName = "CUSTOM";
                    this.specular = tex;                    
                    break;
                case TextureType.BUMP:
                    this.textureName = "CUSTOM";
                    this.bump = tex;
                    break;
                case TextureType.GLOW:
                    this._glowName = "CUSTOM";
                    this.glow = tex;
                    break;
                case TextureType.PARALAX:
                    this._paralaxName = "CUSTOM";
                    this.paralax = tex;
                    break;
                default:
                    throw new Exception("Invalid operation");
            }            
        }



        #endregion

        #region IModelo Members


        public Matrix[] getBonesTransformation()
        {
            Matrix[] m = new Matrix[_model.Bones.Count];
            _model.CopyAbsoluteBoneTransformsTo(m);
            return m;
        }

        #endregion

        #region IModelo Members


        public object getModelTag()
        {
            return _model.Tag;
        }

        #endregion

        #region IModelo Members
        
        /// <summary>
        /// Return null if the dont have this kind of texture
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public Texture2D getTexture(TextureType type)
        {
            if (type == TextureType.DIFFUSE)
            {
                if (textureName != null)
                {
                    return this.texture;
                }
                else
                {
                    BasicEffect basiceffect = _model.Meshes[0].Effects[0] as BasicEffect;
                    return basiceffect.Texture;
                }
            }
            else if(type == TextureType.BUMP)
            {                
                return this.bump;
            }
            else if (type == TextureType.SPECULAR)
            {
                return this.specular;
            }
            else if (type == TextureType.GLOW)
            {
                return this.glow;
            }
            else if (type == TextureType.PARALAX)
            {
                return this.paralax;
            }
                else
            {
                return null;
            }
            


        }

        #endregion

        #region IModelo Members


        public BoundingSphere GetBoudingSphere()
        {
            BoundingSphere bs = new BoundingSphere();
            foreach (ModelMesh item in _model.Meshes)
            {
               bs= BoundingSphere.CreateMerged(bs, item.BoundingSphere);
            }
            return bs;
        }

        BatchInformation[][] batchInformationS = null;
        VertexBuffer[] vertexBufferS = null;
        IndexBuffer[] indexBufferS = null;

        public int MeshNumber
        {
            get { return Model.Meshes.Count; }
        }

        public VertexBuffer GetVertexBuffer(int meshNumber)
        {
            return vertexBufferS[meshNumber];
        }

        public IndexBuffer GetIndexBuffer(int meshNumber)
        {
            return indexBufferS[meshNumber];
        }

        public BatchInformation[] GetBatchInformation(int meshNumber)
        {
            return batchInformationS[meshNumber];
        }

        #endregion

        #region IModelo Members


        public int GetParentBoneIndex(int meshNumber)
        {
            return _model.Meshes[meshNumber].ParentBone.Index;
        }

        #endregion
    }
}
